﻿/*
 * 名称：连接字符串自动生成类
 * 
 * 作用：根据传入参数生成连接字符串。
 *
 * 更新：
 *       2020/06/28 根据原来的Windgoes6.Database.SQLManager，重写此类，把多余的内容全部删除。
 * 
 */

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq; 

namespace WindGoes6.Data.SqlServer
{ 
    /// <summary>
    /// 封装了数据常用的方法，大大减化了数据库的操作。
    /// </summary>
    public class SQLManager
    {
        SqlConnection cn;

        /// <summary>
        /// 默认的连接字符串，在不指定连接字符串的情况下，使用此连接字符串。
        /// </summary>
        public static string DefaultConnectionString { get; set; }

        /// <summary>
        /// 连接字符串。
        /// </summary>
        public static string ConnectionString { get; set; }


        /// <summary>
        /// 需要执行的SQL语句。
        /// </summary>
        public string CommandText { get; set; }

        /// <summary>
        /// 错误消息。
        /// </summary>
        public string ErrorMessage { get; set; }



        /// <summary>
        /// 用于处理数据库连接的
        /// </summary>
        public SQLManager()
        {
            ConnectionString = DefaultConnectionString;
        }

        /// <summary>
        /// 用于处理数据库连接的
        /// </summary>
        /// <param name="connectionString">连接字符串。</param>
        public SQLManager(string connectionString)
        {
            ConnectionString = connectionString;
        }

        /// <summary>
        /// 在指定的超时(timeout)时间内，测试一个连接是否可以连接，如果连接结果以字符串返回。
        /// 其中：Success表示成功，Failed表示失败，其他是错误原因。
        /// </summary>
        /// <param name="connectionString">待测试连接字符串。</param>
        /// <param name="timeout">超时时间，单位：秒，默认值为10。</param>
        /// <returns></returns>
        public static string TestConnection(string connectionString, int timeout = 10)
        {
            string result = "Failed. Reason: ";
            try
            {
                SqlConnection cn = new SqlConnection(connectionString + ";timeout=" + timeout + ";");
                cn.Open();
                cn.Close();
                result = "Success";
            }
            catch (Exception ex)
            {
                result += ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 打开数据库连接.
        /// </summary>
        /// <returns>打开成功返回true,否则返回false</returns>
        public bool OpenCn()
        {
            if (cn == null)
                cn = new SqlConnection(ConnectionString);

            if (cn.State == ConnectionState.Open)
                return true;

            try
            {
                cn.Open();
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
                return false;
            }
            return true;
        }

        /// <summary>
        /// 关闭数据库连接.
        /// </summary>
        /// <returns>关闭成功返回true,否则返回false</returns>
        public bool CloseCn()
        {
            try
            {
                cn.Close();
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
                return false;
            }
            return true;
        }


        /// <summary>
        /// 一般Update和Insert可以用这个方法来实现.
        /// </summary>
        /// <returns>用bool型表示执行结果, true表示成功,否则失败</returns>
        public bool NonQuery(string sql)
        {
            bool result = false;
            if (!OpenCn())
                return false;

            try
            {
                var cmd = cn.CreateCommand();
                cmd.CommandText = sql;
                cmd.ExecuteNonQuery();
                result = true;
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
            }

            CloseCn();
            return result;
        }


        /// <summary>
        /// 一般Select语句用这个方法来实现, 返回结果为字符串二维数组.
        /// </summary>
        /// <returns>若读取失败，则返回空数据。</returns>
        public string[][] GetStrings(string sql)
        {
            List<string[]> data = new List<string[]>();

            if (!OpenCn())
                return data.ToArray();

            try
            {
                var cmd = cn.CreateCommand();
                cmd.CommandText = sql;
                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    string[] strs = new string[reader.FieldCount];
                    for (int i = 0; i < strs.Length; i++)
                        strs[i] = reader[i].ToString();
                    data.Add(strs);
                }
                reader.Close();
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
            }

            CloseCn();

            return data.ToArray();
        }


        /// <summary>
        /// 返回只有单值的sql查询，如count。
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public string GetString(string sql)
        {
            object result = GetObject(sql);
            return result == null ? "" : result.ToString();
        }


        /// <summary>
        /// 只返回第一条记录的数据，如果没有数据，返回长度为0的数据（不为null)。
        /// </summary>
        /// <returns>string[]</returns>
        public string[] GetRow(string sql)
        {
            string[][] data = GetStrings(sql);
            return data.Length > 0 ? data[0] : new string[0];
        }

        /// <summary>
        /// 返回第一列的数据，适合只有一列的操作。
        /// </summary>
        /// <returns></returns>
        public string[] GetColumn(string sql)
        {
            string[][] data = GetStrings(sql);

            if (data == null || data.Length == 0)
                return new string[0];

            string[] str = new string[data.Length];
            for (int i = 0; i < data.Length; i++)
                str[i] = data[i][0];
            return str;
        }


        /// <summary>
        /// 对于只要查询一个数据的查询可以用这个方法
        /// </summary>
        /// <returns>如果没有读取成功，返回为null，否则返回对象。</returns>
        public object GetObject(string sql)
        {
            object obj;
            if (!OpenCn())
                return null;
            try
            {
                var cmd = cn.CreateCommand();
                cmd.CommandText = sql;
                obj = cmd.ExecuteScalar();
            }
            catch
            {
                return null;
            }
            if (!CloseCn())
                return null;
            return obj;
        } 

        /// <summary>
        /// 返回数据集。
        /// </summary> 
        /// <returns></returns>
        public DataSet GetDataSet()
        {
            DataSet ds = new DataSet();
            if (OpenCn())
            {
                var adapter = new SqlDataAdapter(CommandText, ConnectionString);
                adapter.Fill(ds);
                CloseCn();
            }
            return ds;
        }



        /// <summary>
        /// 返回服务器中所有数据库的名称，只支持Sql数据库。
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllDataBaseNames()
        {
            List<string> list = new List<string>();
            string[] data = GetColumn("select name from master..sysdatabases");
            string[] keywords = { "master", "tempdb", "model", "msdb" };
            for (int i = 0; i < data.Length; i++)
                if (!keywords.Contains(data[i].ToLower()))
                    list.Add(data[i]);

            return list;
        }

        /// <summary>
        /// 返回当前数据库中所有的表名。
        /// </summary>
        /// <returns></returns>
        public string[] GetAllTableNames()
        {
            List<string> tableNames = new List<string>();
            //"SELECT name FROM SYSOBJECTS WHERE XTYPE = 'U' 
            if (OpenCn())
            {
                DataTable dt = cn.GetSchema("Tables");
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        if (dt.Rows[i][j] == null || dt.Rows[i][j].ToString().Length == 0)
                        {
                            Console.Write("null" + "\t");
                        }
                        else
                        {
                            Console.Write(dt.Rows[i][j] + "\t");
                        }
                    }
                    Console.WriteLine();
                }
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    if (dt.Rows[i][3].ToString().ToLower() == "base table")
                    {
                        tableNames.Add(dt.Rows[i][2].ToString());
                    }
                }
                CloseCn();
            }
            //commandText =  "SELECT name FROM SYSOBJECTS WHERE XTYPE = 'U'";
            return tableNames.ToArray();
        }
    }
}
